/*    
 * THis file is part of the xoperator SPARQL/XMPP agent.
 * For further information see: http://xoperator.sf.net
 * Copyright (C) 2007  Jörg Unbehauen  

 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>. 
 *
 */
package net.sf.xoperator.store;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.sf.xoperator.blackboard.ConfigurationAwareKnowledgeSource;
import net.sf.xoperator.configuration.KSConfiguration;
import net.sf.xoperator.namespaces.NamespaceSetFlag;
import net.sf.xoperator.rdfxmpp.SPARQLQuery;
import net.sf.xoperator.rdfxmpp.SPARQLResult;
import net.sf.xoperator.ui.MessageToUser;
import net.sf.xoperator.ui.StringMessage;


import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openbbs.blackboard.filter.KindOfFilter;
import org.openbbs.blackboard.ks.KSExecutionContext;

public class RDFStoreHTTPAdaptor extends ConfigurationAwareKnowledgeSource {
	private Log log = LogFactory.getLog(RDFStoreHTTPAdaptor.class);

	private Map<String, RdfStoreInfo> infos = new HashMap<String, RdfStoreInfo>();

	private Object executeQuery(String query, RdfStoreInfo info) {

		HttpClient client = new HttpClient();
		HttpMethod get;
		try {
			// String req = +
			// //+ "&format=application%2Fsparql-results%2Bxml&debug=on";
			// log.info(req);
			get = new GetMethod(info.getEndpointUri());
			String queryParam= "query=" + java.net.URLEncoder.encode(query, "UTF-8");
			if(get.getQueryString()!=null&&!get.getQueryString().isEmpty()){
				queryParam = get.getQueryString() +"&"+queryParam;
			}
			
			get.setQueryString(queryParam );
			
			
			
			
			this.log.info("Querying with: " + get.getURI());
			for (int i = 0; i < get.getRequestHeaders().length; i++) {
				log.info(get.getRequestHeaders()[i].toExternalForm());
			}
			try {
				client.executeMethod(get);
			} catch (IllegalArgumentException e) {
				return new StringMessage(
						"Error in the datastore configuration, check datastore definition for store "
								+ info.getName());
			}
			final String res = get.getResponseBodyAsString();
			if (get.getStatusCode() == 200) {
				return new SPARQLResult(res, info.getName());
			} else {
				
				//strip html from res
				
				
				Pattern pat = Pattern.compile("(<\\!--.*?-->)|(<\\!.*?>)|(<.+?>)",Pattern.DOTALL); 
				String stripRes = pat.matcher(res).replaceAll("").replaceAll("\\s+", " ");
				
				return new StringMessage("Store " + info.getName()
						+ " was unable to execute the query: " + stripRes);
			}

		} catch (UnsupportedEncodingException e1) {
			this.log.error(e1);
			return new StringMessage("Enconding Error while querying store : "
					+ info.getName());
		} catch (IOException e) {
			this.log.error(e);
			return new StringMessage("Error communicating with store "
					+ info.getName());

		}

	}

	@Override
	public void configure(KSConfiguration config) throws Exception {
		RdfStoreInfo info = (RdfStoreInfo) config;
		if (!info.isObsolete()) {
			this.infos.put(info.getName(), info);
		} else {
			this.infos.remove(info.getName());
		}

	}

	@Override
	public void executeInternal(KSExecutionContext context) {
		SPARQLQuery query = (SPARQLQuery) context.blackboard().read(
				new KindOfFilter(SPARQLQuery.class));

		for (RdfStoreInfo info : this.infos.values()) {
			if(query.getStoresToAsk()==null||query.getStoresToAsk().contains(info.getName())){
				context.blackboard().write(executeQuery(query.getQuery(), info));
			}
			

		}
		if (this.infos.size() == 0) {
			context.blackboard().write(new MessageToUser() {
				@Override
				public String getMessage() {
					return "No store replied or no stores defined, unable to answer";
				}
			});
		}

	}

	@Override
	public boolean isEnabledInternal(KSExecutionContext context) {
		SPARQLQuery query = (SPARQLQuery) context.blackboard().read(
				new KindOfFilter(SPARQLQuery.class));
		return context.blackboard().exists(new KindOfFilter(SPARQLQuery.class))
				&& context.blackboard().exists(
						new KindOfFilter(NamespaceSetFlag.class))
				&& !(context.blackboard().exists(
						new KindOfFilter(SPARQLResult.class)) || context
						.blackboard().exists(
								new KindOfFilter(MessageToUser.class)));
	}

	@Override
	public List<Class<? extends KSConfiguration>> getConfigurationClasses() {
		List<Class<? extends KSConfiguration>> classes = new ArrayList<Class<? extends KSConfiguration>>();
		classes.add(RdfStoreInfo.class);
		return classes;
	}

}
